from PyQt5.QtNetwork import (QHostAddress, QTcpServer, QTcpSocket)
from PyQt5.QtCore import QObject, QCoreApplication
import sys
import cv2
import numpy

from Protocol import TextProtocol, TextPtcAssembler

class SocketHandle:
    def handle(self, socket, data):
        pass

class Client(QObject):
    def __init__(self,  socket=None, parent=None):
        super(Client, self).__init__(parent)

        if socket is None:
            self.socket = QTcpSocket()
            self.isClient = True
        else:
            self.socket = socket
            self.isClient = False

        self.handle = None
        self.assembler = TextPtcAssembler()
        self.connectSlots()

    def connectSlots(self):
        self.socket.connected.connect(self.onConnected)
        self.socket.readyRead.connect(self.onReadyRead)

        if self.isClient:
            self.socket.disconnected.connect(self.onDisconnected)

    def connectTo(self, ip, port):
        self.socket.connectToHost(ip, port)
        self.socket.waitForConnected()

    def send(self, data):
        ret = data.serialize()
        self.socket.write(ret)

    def close(self):
        self.socket.close()

    def onConnected(self):
        if self.handle is not None:
            self.handle.handle(self, TextProtocol("CONN", self.socket.peerAddress().toString() + ":" + str(
                self.socket.peerPort())))

    def onDisconnected(self):
        if self.handle is not None:
            self.handle.handle(self, TextProtocol("DSCN", " "))

    def onReadyRead(self):
        data = self.socket.readAll()

        if self.assembler is not None:
            self.assembler.prepare(data, data.__len__())
            while True:
                testmsg = self.assembler.assembler()

                if testmsg is not None:
                    self.handle.handle(self, testmsg)
                else:
                    break

    def setHandle(self, m_handle):
        self.handle = m_handle

    def __del__(self):
        self.socket.close()

class Server(QObject):
    def __init__(self):
        super(Server, self).__init__()
        self.client_list = []
        self.m_handle = None
        self.m_server = QTcpServer()
        self.m_server.newConnection.connect(self.onNewConnection)

    def onNewConnection(self):
        new = self.m_server.nextPendingConnection()

        new_client = Client(new)
        new_client.onConnected()

        if self.m_handle is not None:
            new_client.setHandle(self.m_handle)

        new_client.socket.disconnected.connect(self.onClientDisconnected)

        self.client_list.append(new_client)

        self.m_handle.handle(new_client,
                             TextProtocol("CONN", new.peerAddress().toString() + ":" + str(new.peerPort())))

    def setHandle(self, handle):
        self.m_handle = handle

    def start(self, ip, port):
        if self.m_server.isListening():
            pass
        else:
            self.m_server.listen(QHostAddress(ip), port)
            print(self.m_server.serverAddress())
            print(self.m_server.serverPort())

    def stop(self):
        if self.m_server.isListening():
            self.m_server.close()

    def onClientDisconnected(self):
        ret = 0

        for each in self.client_list:
            if id(each.socket) == id(self.sender()):
                del self.client_list[ret]
            else:
                ret += 1

    def __del__(self):
        self.m_server.close()


class Handle1(SocketHandle):
    def __init__(self):
        self.socket = Server()
        self.socket.setHandle(self)
        self.socket.start("127.0.0.1", 8888)

    def handle(self, socket, data):
        if data.type() == "CONN":
            print(data.data())

        if data.type() == "IMG":
            mdata = data.data()
            try:
                mlen = int(str(mdata[-2:], encoding="utf-8"))
                mlen *= -1
                mlen += -2
                print(str(mdata[mlen:], encoding="utf-8"))
                mdata = mdata[:mlen]
                mdata = numpy.frombuffer(mdata, numpy.uint8)
                decimg = cv2.imdecode(mdata, cv2.IMREAD_COLOR)  # 将数组解码成图像
                cv2.imshow("", decimg)
            except Exception as e:
                print(e)


def main():
    app = QCoreApplication(sys.argv)

    test = Handle1()
    
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
